package repeat;


import java.util.TreeMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// 多线程轮流打印ABC
public class ABCPrint {
    public static void main(String[] args) {
//        ABC_Sync abc_sync = new ABC_Sync();
//        abc_sync.printing();
//        ABC_lock abc_lock = new ABC_lock();
//        abc_lock.printing();
//        ABC_Condition abc_condition = new ABC_Condition();
//        abc_condition.printing();
        ABC_Semaphore abc_semaphore = new ABC_Semaphore();
        abc_semaphore.printing();
    }
}

// synchronized锁,需要保证启动时的有序
class ABC_Sync {

    class ThreadPrinter implements Runnable {
        private String name;
        private Object prev;
        private Object self;

        public ThreadPrinter(String name, Object prev, Object self) {
            this.name = name;
            this.prev = prev;
            this.self = self;
        }

        int count = 10;

        @Override
        public void run() {
            while (count > 0) {
                synchronized (prev) {
                    synchronized (self) { // 前一个打印完，当前锁又拿到
                        System.out.print(name);
                        count--;
                        self.notifyAll();
                    }
                    try {
                        if (count == 0) {
                            prev.notifyAll();
                        } else {
                            prev.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public void printing() {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();

        try {
            new Thread(new ThreadPrinter("A", c, a)).start();
            Thread.sleep(10);
            new Thread(new ThreadPrinter("B", a, b)).start();
            Thread.sleep(10);
            new Thread(new ThreadPrinter("C", b, c)).start();
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// lock，处于一种无序的争抢状态，刚好进到符合条件的线程才有效
class ABC_lock {
    private int state = 0;
    Lock lock = new ReentrantLock();

    class ThreadA implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; ) {
                try {
                    lock.lock(); // 没获取到在此锁住
                    while (state % 3 == 0) {
                        System.out.print("A");
                        state++;
                        i++;
                    }
                }finally{
                    lock.unlock();
                }
            }
        }
    }
    class ThreadB implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; ) {
                try {
                    lock.lock(); // 没获取到在此锁住
                    while (state % 3 == 1) {
                        System.out.print("B");
                        state++;
                        i++;
                    }
                }finally{
                    lock.unlock();
                }
            }
        }
    }
    class ThreadC implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; ) {
                try {
                    lock.lock(); // 没获取到在此锁住
                    while (state % 3 == 2) {
                        System.out.print("C");
                        state++;
                        i++;
                    }
                }finally{
                    lock.unlock();
                }
            }
        }
    }
    public void printing(){
        new Thread(new ThreadA()).start();
        new Thread(new ThreadB()).start();
        new Thread(new ThreadC()).start();
    }
}

// ReentrantLock+condition
class ABC_Condition{
    private Lock lock= new ReentrantLock();
    Condition ca = lock.newCondition();
    Condition cb = lock.newCondition();
    Condition cc = lock.newCondition();
    private int state = 0;

    class ThreadA implements Runnable{
        @Override
        public void run() {
            lock.lock();
            try {
                for (int i = 0; i < 10; i++) {

                    while (state % 3 != 0){
                        ca.await();
                    }
                    System.out.print("A");
                    cb.signal();
                    state++;
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
    class ThreadB implements Runnable{
        @Override
        public void run() {
            lock.lock();
            try {
                for (int i = 0; i < 10; i++) {

                    while (state % 3 != 1){
                        cb.await();
                    }
                    System.out.print("B");
                    cc.signal();
                    state++;
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
    class ThreadC implements Runnable{
        @Override
        public void run() {
            lock.lock();
            try {
                for (int i = 0; i < 10; i++) {

                    while (state % 3 != 2){
                        cc.await();
                    }
                    System.out.print("C");
                    ca.signal();
                    state++;
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
    public void printing(){
        new Thread(new ThreadA()).start();
        new Thread(new ThreadB()).start();
        new Thread(new ThreadC()).start();
    }

}

// Semaphore
class ABC_Semaphore{
    private Semaphore sa = new Semaphore(1);
    private Semaphore sb = new Semaphore(0);
    private Semaphore sc = new Semaphore(0);

    class ThreadA implements Runnable{

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {

                    sa.acquire();
                    System.out.print("A");
                    sb.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    class ThreadB implements Runnable{

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {

                    sb.acquire();
                    System.out.print("B");
                    sc.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    class ThreadC implements Runnable{

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {

                    sc.acquire();
                    System.out.print("C");
                    sa.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    public void printing(){
        new Thread(new ThreadA()).start();
        new Thread(new ThreadB()).start();
        new Thread(new ThreadC()).start();
    }
}

